try:
     import xml.etree.cElementTree as etree
except ImportError:
     import xml.etree.ElementTree as etree

import py3func
LOG = py3func.make_logging(__file__)

from xml2dict.xml2dict import XmlNode
from parsermk.btnparser import DataBtnParser

class SvgParser:
    def __init__(self):
        # self.xml_elem_root = None
        pass

    def load_from_file(self, file_path):
        tree = etree.parse(file_path)
        self.xml_elem_root = tree.getroot()

    def _get_elem_attr(self, xml_elem, attr_name):
        return xml_elem.attrib[attr_name]

    def get_whole_size(self):
        """ return a tuple of (width, height) """
        width = self._get_elem_attr(self.xml_elem_root, "width")
        height = self._get_elem_attr(self.xml_elem_root, "height")
        return (width, height)

    def get_elems_geometry(self, btn_list_to_search=None):
        """ return a dict like {"id_xxx":("x", "y", "width", "height")} """
        dict_rect = {}
        for elem_rect in self.xml_elem_root:  # tuple(root_elem)
            attri_rect = ("x", "y", "width", "height")
            if btn_list_to_search and elem_rect.attrib["id"] not in btn_list_to_search:
                continue
            dict_rect[elem_rect.attrib["id"]] = [int(elem_rect.attrib[item]) for item in attri_rect]
        return dict_rect


class XmlParser:
    def __init__(self):
        self.dict_xnode_data = {}  # xml文件原始数据集
        self.dict_pages_data = {}  # keyboard-page应用数据集
        self.dict_wnd_attrib = {}

    def load_xml(self, file_path):
        xml_node = XmlNode()
        xml_node.load_from_file(file_path, "xml")
        self.dict_xnode_data = xml_node.dump_to_dict()
        self._xmlelem_to_keydata()
        self._try_loading_svg()

    def _xmlelem_to_keydata(self):
        if len(self.dict_xnode_data) != 1:
            raise Exception("Data Root Number Error.")
        node_root = list(self.dict_xnode_data.values())[0]  # node_root is a tuple

        # parse keywnd attribute
        self.dict_wnd_attrib = node_root[1]

        # parse the page layer
        if "page" not in node_root[2]:
            raise Exception("No page found in the xml.")
        # self.dict_pages_data = {}  # self.dict_pages_data is a dict
        node_pages = node_root[2]["page"]  # node_pages is a tuple or a list

        for node_page in node_pages:
            if "id" not in node_page[1]:
                raise Exception("No [id] found in this page's attribute.")
            str_id = node_page[1]["id"]
            # 由于需要更换page[2]为另一类型dict，需要将node_pages由tuple转为list
            self.dict_pages_data[str_id] = list(node_page)
            # 此时，self.keypages_data已经与self.xmlnode_data分离(解除浅复制关联)

        # parse the button layer
        for page_id, node_page in self.dict_pages_data.items():
            # page_id is a string, node_page is a tuple
            new_node_btns = {}
            if "btn" not in node_page[2]:
                raise Exception("No button list found in \"%s\" page." % page_id)
            node_btns = node_page[2]["btn"]  # node_pages is a tuple or a list
            for node_btn in node_btns:
                if "id" not in node_btn[1]:
                    raise Exception("No [id] found in this btns's attribute.")
                str_id = node_btn[1]["id"]
                new_node_btns[str_id] = node_btn
            node_page[2] = new_node_btns

        # Now the structure of node_pages is:
        """
        self.dict_pages_data = {
            "MP0":  [
                        None,
                        {"id": "MP0", "x": 0, "y": 0 }
                        {
                            "FA0101": ( None,
                                        {"image": "./a.png"},
                                        {
                                            "key": [( None, {}, None), () ... ] ,
                                            "plc": [( None, {}, None), () ... ] ,
                                            "shell": [( None, {}, None), () ... ]
                                        }
                                      ),
                            # next_button ...
                        }
                    ],
            # next_page ...
        }
        """

    def get_xml_origin_data(self):
        """ depressed, self.dict_xnode_data should be private,
            and as the constraint of MVC model,
            all data should be provided by interface.
        """
        if not self.dict_xnode_data:
            raise Exception("No Valid Data in the Object.")
        return self.dict_xnode_data

    # def save_to_file(self):
    #     pass

    def _try_loading_svg(self):
        for page_id, node_page in self.dict_pages_data.items():
            if "svgfile" not in node_page[1]:
                # raise Exception("No SVG file found in the xml[page].")
                break
            svg = SvgParser()
            svg.load_from_file(node_page[1]["svgfile"])
            list_btn_names = self.get_btns_name_list(page_id)
            dict_data_svg = svg.get_elems_geometry(list_btn_names)

            # 修改btn层级，向self.dict_pages_data中增加参数
            for btn_id, node_btn in node_page[2].items():
                ge_item = ["x", "y", "w", "h"]
                for index in range(4):
                    if btn_id not in dict_data_svg:
                        continue
                    node_btn[1][ge_item[index]] = dict_data_svg[btn_id][index]

    # def check_attribute(self, id, key, not_found_strategy):  ??
    #     """ return a string of attribute value """

    def get_wnd_geometry(self):
        """ return (x, y, w, h) """
        return [int(self.dict_wnd_attrib[item]) for item in ["x", "y", "w", "h"]]

    def get_wnd_default_page(self):
        """ return the string of default_page's ID """
        if "default_page" in self.dict_wnd_attrib:
            return self.dict_wnd_attrib["default_page"]
        elif len(self.dict_pages_data) == 1:
            return list(self.dict_pages_data.keys())[0]
        else:
            raise Exception("No [default_page] found in this window's attribute, \
                             and there is more than one page in this keyboard config file.")

    def get_wnd_qssfile(self):
        """ return the string of qssfile or None """
        if "qssfile" in self.dict_wnd_attrib:
            return self.dict_wnd_attrib["qssfile"]
        # else:
        #     return None

    def get_page_svgfile(self, page_id):
        """ svgfile has used to add each button the geometry attribute,
            user has no neeed to use it anymore
        """
        pass

    def get_page_imgfile(self, page_id):
        if "image" in self.dict_pages_data[page_id][1]:
            return self.dict_pages_data[page_id][1]["image"]

    def get_btns_name_list(self, page_id):
        """ return a list of btn's names """
        return list(self.dict_pages_data[page_id][2].keys())

    def get_btn_parser(self, page_id):
        return DataBtnParser(self.dict_pages_data[page_id][2])


if __name__ == "__main__":
    xml = XmlParser()
    xml.load_xml("./sample/information.xml")

    print("XML Origin Infomation -->\n", xml.dict_xnode_data)
    print("-------------------------------------------------------")
    print("XmlNode Informatino -->\n", xml.dict_pages_data)

    # btn_parser = xml.get_btn_parser("MP0")
    # print(btn_parser.geometry("FA0101"))

